#include "blockqueue.hpp"
#include "task.hpp"
#include <cstdlib>
#include <ctime>
#include <unistd.h>

string ops = "+-*/%";

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void* product(void* args)
{
    blockQueue<c_task>* cbq = ((blockQueues<c_task, s_task>*)args)->_cbq;
    while (true)
    {
        //int data = rand() % 10 + 1;//生产数据
        int x = rand() % 10 + 1;
        int y = rand() % 5 + 1;
        int opIndex = rand() % 5;
        c_task t(x, y, ops[opIndex], Compute);
        //cbq->push(data);
        cbq->push(t);//一个生产线程生产后 其他生产线程可能竞争不过消费线程 也可能竞争不过 所以无法生产一批消费一批
        pthread_mutex_lock(&lock);
        cout << "productor:" << t.toTaskString() << endl;
        pthread_mutex_unlock(&lock);
        sleep(2);//生产慢消费快 生产一条消费一条
    } 
    return nullptr;
}

void* consume(void* args)
{
    blockQueue<c_task>* cbq = ((blockQueues<c_task, s_task>*)args)->_cbq;
    //blockQueue<string>* sbq = ((blockQueues*)args)->_sbq;
    while (true)
    {
        //int data;
        //bq->pop(&data);
        //处理计算任务
        c_task ct;
        cbq->pop(&ct);
        string result = ct();
        pthread_mutex_lock(&lock);
        cout << "consumer:" << result << endl;
        pthread_mutex_unlock(&lock);
        //推送计算结果
        // s_task st(result, Save);
        // cout << "consumer: 推送计算结果..." << endl;
        // sbq->push(st);

        //sleep(1);//消费慢生产快 开始生产多条消费一条 后续生产一条消费一条
    }
    return nullptr;
}

/*
引入保存者线程 将消费者线程的计算结果保存到文件中
那么 对于消费者线程来说既充当生产者又充当消费者 既要处理队列中的数据 又要将处理结果推送至队列中
其中 两个队列不能为同一个队列 一个队列存放计算任务 一个队列存放保存任务
*/
// void* save(void* args)
// {
//     blockQueue<s_task>* sbq = ((blockQueues<c_task, s_task>*)args)->_sbq;
//     while (true)
//     {
//         s_task t;
//         sbq->pop(&t);
//         cout << "saver: 保存计算结果..." << endl;
//         Save(t());
//     }
//     return nullptr;
// }


int main()
{
    srand((unsigned int)time(nullptr));
    blockQueues<c_task, s_task> bqs;
    pthread_t productors[3], consumers[3];//引入多生产多消费
    /*
    为什么说生产消费模型是高效的？
    在一个线程访问临界区或在条件变量上等待时 其他线程可以并发执行临界区外的代码 如任务构造 任务处理等
    因此在保证线程安全的同时 合理利用了cpu的时间片
    */
    pthread_create(productors, nullptr, product, &bqs);
    pthread_create(productors + 1, nullptr, product, &bqs);
    pthread_create(productors + 2, nullptr, product, &bqs);
    pthread_create(consumers, nullptr, consume, &bqs);
    pthread_create(consumers + 1, nullptr, consume, &bqs);
    pthread_create(consumers + 2, nullptr, consume, &bqs);

    for (int i = 0; i < 3; i++)
    {
        pthread_join(productors[i], nullptr);
    }
    for (int i = 0; i < 3; i++)
    {
        pthread_join(consumers[i], nullptr);
    }

    // pthread_create(&productor, nullptr, product, &bqs);
    // pthread_create(&consumer, nullptr, consume, &bqs);
    //pthread_create(&saver, nullptr, save, &bqs);
    // pthread_join(productor, nullptr);
    // pthread_join(consumer, nullptr);
    // pthread_join(saver, nullptr);
    return 0;
}
